/*
 * GenerateMatrix.java
 *
 * Created on April 12, 2004, 10:31 AM
 */

package com.milowski.monos.component;

import java.io.*;
import java.util.*;

import com.milowski.monos.*;
import com.milowski.monos.monomial.*;
import com.milowski.monos.binomial.*;
import org.infoset.component.Component;
import org.infoset.component.ItemFilterComponent;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.filter.SubtreeFilter;

/**
 *
 * @author  R. Alexander Milowski
 */
public class FormulateGapLPComponent extends MonosComponentBase  {
   
   
   static final Name componentName = InfosetFactory.createName(XML.STEPS_NAMESPACE,"column-sum-matrix");;
   static Name [] subtreeNames = { XML.formulateGapName };

   public static class ComponentFilter extends SubtreeFilter {
      
      int rowCount;
   
      ComponentFilter() {
         super(subtreeNames);
      }
      public void process(Document doc) 
         throws XMLException
      {
         Element top = doc.getDocumentElement();

         Iterator<Element> children = top.getElementChildren();
         MatrixBasis matrix = (MatrixBasis)XML.unmarshall(children.next());
         Monomial cost = (Monomial)XML.unmarshall(children.next());
         LexOrderedList components = (LexOrderedList)XML.unmarshall(children.next());

         ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
         post(constructor.createElement(XML.componentLPListName));
         generate(constructor, matrix, cost.getValues(), components);
         post(constructor.createElementEnd(XML.componentLPListName));
      }

      protected String arrayToString(int []a) {
         StringBuffer sb = new StringBuffer();
         for (int i=0; i<a.length; i++) {
            if (i!=0) {
               sb.append(' ');
            }
            sb.append(Integer.toString(a[i]));
         }
         return sb.toString();
      }

      protected String arrayToString(short []a) {
         StringBuffer sb = new StringBuffer();
         for (int i=0; i<a.length; i++) {
            if (i!=0) {
               sb.append(' ');
            }
            sb.append(Short.toString(a[i]));
         }
         return sb.toString();
      }

      public void generate(ItemConstructor constructor,MatrixBasis matrix,short cost[],LexOrderedList dcomp)
         throws XMLException
      {
         Iterator components = dcomp.iterator();
         int count = 1;
         int rowCount = matrix.getRowCount();
         int colCount = matrix.getColumnCount();
         while (components.hasNext()) {
            MonomialIdeal c = (MonomialIdeal)components.next();
            StringWriter out = new StringWriter();
            Monomial lcm = IdealGenerator.lcm(c);
            short [] u = lcm.getValues();
            boolean ok = false;
            for (int i=0; i<u.length; i++) {
               if (u[i]>1) {
                  ok = true;
               }
            }
            if (!ok) {
               continue;
            }
            boolean [] upart = new boolean[u.length];
            int [] b = new int[rowCount];
            for (int i=0; i<b.length; i++) {
               b[i] = 0;
            }
            int ucount = 0;
            for (int i=0; i<u.length; i++) {
               upart[i] = false;
               if (u[i]>0) {
                  upart[i] = true;
                  ucount++;
                  u[i]--;
                  if (u[i]>0) {
                     for (int j=0; j<b.length; j++) {
                        b[j] += u[i]*matrix.get(j,i);
                     }
                  }
               }
            }
            out.write("H-representation\n");
            out.write("begin\n");
            out.write("   "+(rowCount*2+ucount)+" "+(colCount+1)+" rational\n");
            for (int i=0; i<u.length; i++) {
               if (upart[i]) {
                  out.write("   0 ");
                  for (int j=0; j<u.length; j++) {
                     out.write(j==i ? "1 " : "0 ");
                  }
                  out.write("\n");
               }
            }
            for (int i=0; i<rowCount; i++) {
               out.write("   "+b[i]+" ");
               for (int j=0; j<colCount; j++) {
                  out.write((-matrix.get(i,j))+" ");
               }
               out.write("\n");
               out.write("   "+(-b[i])+" ");
               for (int j=0; j<colCount; j++) {
                  out.write(matrix.get(i,j)+" ");
               }
               out.write("\n");
            }
            out.write("end\n");
            out.write("maximize\n");
            out.write("   ");
            int constant = 0;
            for (int i=0; i<cost.length; i++) {
               constant += u[i]*cost[i];
            }
            out.write(constant+" ");
            for (int i=0; i<cost.length; i++) {
               out.write((-cost[i])+" ");
            }
            out.write("\n");
            out.flush();

            Element lp = constructor.createElement(XML.componentLPName);
            lp.setAttributeValue("constant", Integer.toString(constant));
            post(lp);
            c.toXML(constructor, output);
            post(constructor.createElement(XML.linearProgramName));

            post(constructor.createCharacters(out.toString()));
            post(constructor.createElementEnd(XML.linearProgramName));

            post(constructor.createElement(XML.cName));
            post(constructor.createCharacters(arrayToString(cost)));
            post(constructor.createElementEnd(XML.cName));
            post(constructor.createElement(XML.uName));
            post(constructor.createCharacters(arrayToString(u)));
            post(constructor.createElementEnd(XML.uName));
            post(constructor.createElement(XML.bName));
            post(constructor.createCharacters(arrayToString(b)));
            post(constructor.createElementEnd(XML.bName));
            post(constructor.createElementEnd(XML.componentLPName));
            count++;
         }
      }

      
   }
   
   /** Creates a new instance of KernelBasisComponent */
   public FormulateGapLPComponent()
   {
      super(componentName);
   }
   
   public Component newInstance() 
      throws XMLException
   {
      final ComponentFilter filter = new ComponentFilter();
      return new ItemFilterComponent(name,vendor,version,filter,inputPortName,outputPortName);
   }
   

}
